package com.qingfeng.openplantform.getway.filters;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.qianfeng.openplantform.commons.beans.BaseResultBean;
import com.qianfeng.openplantform.commons.constans.ExceptionDict;
import com.qianfeng.openplantform.commons.constans.SystemParams;
import com.qingfeng.openplantform.getway.feign.CacheService;
import com.qingfeng.openplantform.getway.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;

@Component
public class SignFilter extends ZuulFilter {

    @Autowired
    private CacheService cacheService;
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 30;
    }

    @Override
    public boolean shouldFilter() {
        return RequestContext.getCurrentContext().sendZuulResponse();
    }

    @Override
    public Object run() throws ZuulException {

        //对用户传递的数据和签名进行判断

        //获取用户传递参数
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        //对参数除了签名外的数据进行排序
        Map<String, String> paraMaps = new TreeMap<>();//TreeMap是什么东西
        Enumeration<String> parameterNames = request.getParameterNames();
        while (((Enumeration) parameterNames).hasMoreElements()) {
            String paramName = parameterNames.nextElement();//获取当前的参数名
            if ("sign".equalsIgnoreCase(paramName)) {//签名数据不能参数签名运算,因为它是签名运算的结果
                continue;
            }
            String value = request.getParameter(paramName);
            paraMaps.put(paramName, value);//将参数放到一个 m p 中,这个 map 是 treemap
        }

        //排序后拼接用户的盐值,每个用户应该都不一样,否则的话就没有意义

        //需要先获取当前用户是谁,如何知道当前用户是谁,我们要求用户必须传递app_key来告诉我们他是谁,然后我们去获取他的盐值
        String app_key = request.getParameter("app_key");//获取到当前应用的 appkey 标记,类似于用户的 id
        //根据用户找到用户的盐值
        try {
            //获取应用在 redis 中的信息
            Map<Object, Object> appInfo = cacheService.hGetAll(SystemParams.CUSTOMER_REDIS_PRE + app_key);
            if (appInfo != null && appInfo.size() > 0) {
                //代表有数据
                Object appSecret = appInfo.get("appSecret");//获取appSecret
                if (appSecret != null) {
                    //代表找到了盐值
                    //生成签名
                    String md5Signature = Md5Util.md5Signature(paraMaps, appSecret.toString());//把用户传递过来的数据进行签名,得到一个我们算出来它应该传递的签名
                    System.err.println("用户应该传递的签名:"+md5Signature);
                    //获取用户传递的签名
                    String sign = request.getParameter("sign");//用户传递过来的
                    System.err.println("用户传递的签名:"+sign);
                    //比较两个值是不是一样
                    if (md5Signature.equalsIgnoreCase(sign)) {
                        //校验成功,直接放行
                        return null;
                    }
                }else{
                    //没有盐值,抛出异常
                    System.err.println("没有找到用户的盐值");
                }
            } else {
                //没有找到应用相关的信息,代表 app_key 传递错误,返回 app_key 错误的相关提示
                System.err.println("没有找到对应的 app_key 相关的信息");
            }
        } catch (Exception e) {
            e.printStackTrace();
            //返回异常信息
        }
        //代码执行到这里说明上面的签名是校验失败的
        context.setSendZuulResponse(false);//拦截请求
        BaseResultBean baseResultBean = new BaseResultBean();
        baseResultBean.setMsg("签名校验失败");
        baseResultBean.setCode(ExceptionDict.SYSTEMPARAM_SING_ERROR);
        String json = null;
        try {
            json = objectMapper.writeValueAsString(baseResultBean);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        context.getResponse().setContentType("application/json;charset=utf-8");
        context.setResponseBody(json);

        return null;

    }
}
